package com.songlanyun.modules.memberbill.service.impl;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.songlanyun.common.enums.BillConstant;
import com.songlanyun.common.enums.IntegralConstant;
import com.songlanyun.common.exception.RRException;
import com.songlanyun.common.utils.PageUtils;
import com.songlanyun.common.utils.Query;
import com.songlanyun.common.utils.custom.MathUtils;
import com.songlanyun.common.utils.custom.PatternUtils;
import com.songlanyun.config.ChainProperties;
import com.songlanyun.modules.account.entity.AccountEntity;
import com.songlanyun.modules.account.entity.UserIdentityAssetEntity;
import com.songlanyun.modules.account.entity.UserVerifiedEntity;
import com.songlanyun.modules.account.service.AccountService;
import com.songlanyun.modules.account.service.UserIdentityAssetService;
import com.songlanyun.modules.account.service.UserVerifiedService;
import com.songlanyun.modules.account.service.impl.UserIdentityAssetServiceImpl;
import com.songlanyun.modules.balacegiveaway.entity.BalanceGiveAwayEntity;
import com.songlanyun.modules.balacegiveaway.service.BalanceGiveAwayService;
import com.songlanyun.modules.chain.service.ChainService;
import com.songlanyun.modules.integralrecord.entity.IntegralRecord;
import com.songlanyun.modules.integralrecord.service.IntegralRecordService;
import com.songlanyun.modules.memberbill.dao.SaleRefillCardBillDao;
import com.songlanyun.modules.memberbill.dao.SaleRefillVoucherBillDao;
import com.songlanyun.modules.memberbill.entity.*;
import com.songlanyun.modules.memberbill.service.SaleRefillCardBillService;
import com.songlanyun.modules.memberbill.service.SaleRefillVoucherBillService;
import com.songlanyun.modules.pointconfig.entity.PointConfig;
import com.songlanyun.modules.pointconfig.service.PointConfigService;
import com.songlanyun.modules.pointtobalace.entity.BalanceToPointRecordEntity;
import com.songlanyun.modules.pointtobalace.entity.PointToBalanceRecordEntity;
import com.songlanyun.modules.pointtobalace.service.BalanceToPointRecordService;
import com.songlanyun.modules.pointtobalace.service.PointToBalanceRecordService;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;


@Service("yxtSaleRefillVoucherBillService")
public class SaleRefillVoucherBillServiceImpl extends ServiceImpl<SaleRefillVoucherBillDao, SaleRefillVoucherBillEntity> implements SaleRefillVoucherBillService {


    @Resource
    private UserIdentityAssetService userIdentityAssetService;

    @Autowired
    private AccountService accountService;

    @Autowired
    private PointConfigService pointConfigService;

    @Autowired
    private IntegralRecordService integralRecordService;

    @Autowired
    private UserVerifiedService userVerifiedService;

    @Autowired
    private PointToBalanceRecordService pointToBalanceRecordService;

    @Autowired
    private BalanceGiveAwayService balanceGiveAwayService;

    @Autowired
    private BalanceToPointRecordService balanceToPointRecordService;

    @Autowired
    private SaleRefillVoucherBillDao saleRefillVoucherBillDao;

    @Resource
    ChainService chainService;
    @Resource
    ChainProperties chainProperties;






    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        Long userId = MapUtil.getLong(params, "user_id");//会员id
        Integer billType = MapUtil.getInt(params, "bill_type");//收支类型
        String refillOrderCode = MapUtil.getStr(params, "refill_order_code");//充值卡订单
        String saleOrderCode = MapUtil.getStr(params, "sale_order_code");//消费订单

        IPage<SaleRefillVoucherBillEntity> page = this.page(
                new Query<SaleRefillVoucherBillEntity>().getPage(params),
                new LambdaQueryWrapper<SaleRefillVoucherBillEntity>()
                        .eq(userId != null, SaleRefillVoucherBillEntity::getUserId, userId)
                        .eq(billType != null, SaleRefillVoucherBillEntity::getBillType, billType)
                        .like(StringUtils.isNotBlank(refillOrderCode), SaleRefillVoucherBillEntity::getRefillOrderCode, refillOrderCode)
                        .like(StringUtils.isNotBlank(saleOrderCode), SaleRefillVoucherBillEntity::getSaleOrderCode, saleOrderCode)
                        .orderByDesc(SaleRefillVoucherBillEntity::getCreateTimeMillis)

        );

        return new PageUtils(page);
    }

    /**
     * 生成收入账单
     *
     * @param userIdentity 会员资产
     * @param addMoney     收入金额
     * @param innerMode    收入行为（0充值，1退款余回退）
     * @param outTradeNo   充值订单编号
     */
    @Override
    public void saveIncomeBill(UserIdentityAssetEntity userIdentity, BigDecimal addMoney, String outTradeNo, BillConstant.InnerMode innerMode) {
        SaleRefillVoucherBillEntity bill = new SaleRefillVoucherBillEntity();
        bill.setRemark(innerMode.getMsg());//账单说明
        bill.setBillType(BillConstant.BillMode.INCOME);//账单类型
        bill.setEntryBeforeBalance(userIdentity.getBalance().subtract(addMoney));//入帐前的余额
        bill.setEntryAfterBalance(userIdentity.getBalance());//入帐后的余额
        bill.setEntryValue(addMoney);//入帐的额度
        bill.setRefillOrderCode(outTradeNo);//充值订单编号

        bill.setInnerMode(innerMode);//收入的行为模式（0充值，1退款余回退）
        bill.setCreateTimeMillis(System.currentTimeMillis());//创建帐户的时间戳
        bill.setUserId(userIdentity.getId());//会员id

        saleRefillVoucherBillDao.insert(bill);
    }

    @Override
    public void saveIncomeBill(UserIdentityAssetEntity userIdentity, BigDecimal addMoney, String outTradeNo, BillConstant.InnerMode innerMode,String remark) {
        SaleRefillVoucherBillEntity bill = new SaleRefillVoucherBillEntity();
        bill.setRemark(remark);//账单说明
        bill.setBillType(BillConstant.BillMode.INCOME);//账单类型
        bill.setEntryBeforeBalance(userIdentity.getBalance().subtract(addMoney));//入帐前的余额
        bill.setEntryAfterBalance(userIdentity.getBalance());//入帐后的余额
        bill.setEntryValue(addMoney);//入帐的额度
        bill.setRefillOrderCode(outTradeNo);//充值订单编号或其它业务编号

        bill.setInnerMode(innerMode);//收入的行为模式（0充值，1退款余回退）
        bill.setCreateTimeMillis(System.currentTimeMillis());//创建帐户的时间戳
        bill.setUserId(userIdentity.getId());//会员id

        saleRefillVoucherBillDao.insert(bill);
    }

    /**
     * 生成支出账单
     *
     * @param userIdentity 会员资产
     * @param subMoney     支出金额
     * @param outTradeNo   充值订单编号
     * @param outerModel   支出行为（0普通消费）
     */
    @Override
    public void saveExpenditureBill(UserIdentityAssetEntity userIdentity, BigDecimal subMoney, String outTradeNo, BillConstant.OuterMode outerModel) {
        SaleRefillVoucherBillEntity bill = new SaleRefillVoucherBillEntity();
        bill.setRemark(outerModel.getMsg());//账单说明
        bill.setBillType(BillConstant.BillMode.EXPENDITURE);//账单类型
        bill.setEntryBeforeBalance(userIdentity.getBalance().add(subMoney));//入帐前的余额
        bill.setEntryAfterBalance(userIdentity.getBalance());//入帐后的余额
        bill.setEntryValue(subMoney);//入帐的额度

        bill.setSaleOrderCode(outTradeNo);//消费订单编号
        bill.setOuterMode(outerModel);//支出（0普通消费）
        bill.setCreateTimeMillis(System.currentTimeMillis());//创建帐户的时间戳
        bill.setUserId(userIdentity.getId());//会员id

        saleRefillVoucherBillDao.insert(bill);
    }

    @Override
    public void saveExpenditureVoucherBill(UserIdentityAssetEntity userIdentity, BigDecimal subMoney, String outTradeNo, BillConstant.OuterMode outerModel) {
        SaleRefillVoucherBillEntity bill = new SaleRefillVoucherBillEntity();
        bill.setRemark(outerModel.getMsg());//账单说明
        bill.setBillType(BillConstant.BillMode.EXPENDITURE);//账单类型
        bill.setEntryBeforeBalance(userIdentity.getBalance().add(subMoney));//入帐前的余额
        bill.setEntryAfterBalance(userIdentity.getBalance());//入帐后的余额
        bill.setEntryValue(subMoney);//入帐的额度

        bill.setSaleOrderCode(outTradeNo);//消费订单编号
        bill.setOuterMode(outerModel);//支出（0普通消费）
        bill.setCreateTimeMillis(System.currentTimeMillis());//创建帐户的时间戳
        bill.setUserId(userIdentity.getId());//会员id


        saleRefillVoucherBillDao.insert(bill);
    }

    @Override
    public void saveExpenditureBill(UserIdentityAssetEntity userIdentity, BigDecimal subMoney, String outTradeNo, BillConstant.OuterMode outerModel,String remark) {
        SaleRefillVoucherBillEntity bill = new SaleRefillVoucherBillEntity();
        bill.setRemark(remark);//账单说明
        bill.setBillType(BillConstant.BillMode.EXPENDITURE);//账单类型
        bill.setEntryBeforeBalance(userIdentity.getBalance().add(subMoney));//入帐前的余额
        bill.setEntryAfterBalance(userIdentity.getBalance());//入帐后的余额
        bill.setEntryValue(subMoney);//入帐的额度

        bill.setSaleOrderCode(outTradeNo);//消费订单编号
        bill.setOuterMode(outerModel);//支出（0普通消费）
        bill.setCreateTimeMillis(System.currentTimeMillis());//创建帐户的时间戳
        bill.setUserId(userIdentity.getId());//会员id

        saleRefillVoucherBillDao.insert(bill);
    }

    @Override
    public List<SaleRefillVoucherBillEntity> getUserBill(Long userId) {
        return this.saleRefillVoucherBillDao.selectList(
                new LambdaQueryWrapper<SaleRefillVoucherBillEntity>()
                        .eq(SaleRefillVoucherBillEntity::getUserId, userId)
                        .orderByDesc(SaleRefillVoucherBillEntity::getCreateTimeMillis)

        );
    }

    @Override
    public PageUtils getUserBillPage(Long userId, Map<String, Object> params) {
        Integer billType = MapUtil.getInt(params, "bill_type");

        IPage<SaleRefillVoucherBillEntity> page = this.page(
                new Query<SaleRefillVoucherBillEntity>().getPage(params),
                new LambdaQueryWrapper<SaleRefillVoucherBillEntity>()
                        .eq(SaleRefillVoucherBillEntity::getUserId, userId)
                        .eq(billType != null, SaleRefillVoucherBillEntity::getBillType, billType)
                        .orderByDesc(SaleRefillVoucherBillEntity::getCreateTimeMillis)
        );

        return new PageUtils(page);
    }

    /**
     * 增加金额  --生成收入账单
     *
     * @param userId     用户id
     * @param addMoney   收入金额
     * @param outTradeNo 充值订单编号
     * @param innerMode  收入行为（0充值，1退款余回退）
     */
    @Override
    public void addBalance(Long userId, BigDecimal addMoney, String outTradeNo, BillConstant.InnerMode innerMode) {

        UserIdentityAssetEntity userIdentity = userIdentityAssetService.updateBalance(userId, addMoney, true);
        //生成充值订单账单明细，保存收入账单
        this.saveIncomeBill(userIdentity, addMoney, outTradeNo, innerMode);
    }

    @Override
    public void addBalance(Long userId, BigDecimal addMoney, String outTradeNo, BillConstant.InnerMode innerMode,String remark) {

        UserIdentityAssetEntity userIdentity = userIdentityAssetService.updateVoucher(userId, addMoney, true);
        //生成充值订单账单明细，保存收入账单
        this.saveIncomeBill(userIdentity, addMoney, outTradeNo, innerMode,remark);
    }

    /**
     * 减少金额 --生成支出账单
     *
     * @param userId     用户id
     * @param subMoney   支出金额
     * @param outTradeNo 充值订单编号
     *                   outerModel   支出行为（0普通消费）
     */
    @Override
    public void subBalance(Long userId, BigDecimal subMoney, String outTradeNo, BillConstant.OuterMode outerModel) {

        //资产
        UserIdentityAssetEntity userIdentity = userIdentityAssetService.updateBalance(userId, subMoney, false);

        //生成充值订单账单明细，保存支出账单
        this.saveExpenditureBill(userIdentity, subMoney, outTradeNo, outerModel);
    }

    @Override
    public void subBalance(Long userId, BigDecimal subMoney, String outTradeNo, BillConstant.OuterMode outerModel,String remark) {

        //资产
        UserIdentityAssetEntity userIdentity = userIdentityAssetService.updateBalance(userId, subMoney, false);

        //生成充值订单账单明细，保存支出账单
        this.saveExpenditureBill(userIdentity, subMoney, outTradeNo, outerModel,remark);
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void pointToBalance(Long userId, PointToBalanceDTO dto) {
        AccountEntity account = accountService.getUserById(userId, true);
        UserVerifiedEntity optionUserVerifiedEntity = userVerifiedService.loadById(userId, false);
        if(ObjectUtil.isNull(optionUserVerifiedEntity))
        {
            throw new RRException("您还没有实名认证不能兑换");
        }

        UserIdentityAssetEntity optionUserAssetEntity = userIdentityAssetService.loadByIdForLock(userId, true);
        String pass = new Sha256Hash(dto.getPayPassword(), UserIdentityAssetServiceImpl.PASS_SALT).toHex();
        if(ObjectUtil.isEmpty(optionUserAssetEntity.getPayPass()))
        {
            throw new RRException("支付密码没设置",99999);
        }

        if(!optionUserAssetEntity.getPayPass().equals(pass))
        {
            throw new RRException("支付密码错误");
        }

        if(optionUserAssetEntity.getIntegralAble().compareTo(dto.getValue())<0)
        {
            throw new RRException("您的可用积分不足");
        }


        PointConfig config = pointConfigService.loadConfig(true);

//        BigDecimal giveAwayHandlingFeeRatio = config.getGiveAwayHandlingFeeRatio();
//        BigDecimal handlingFee = MathUtils.setScaleDown(dto.getValue().doubleValue() * giveAwayHandlingFeeRatio.doubleValue() / 100, 8);
//        BigDecimal facePoint = MathUtils.setScaleDown(dto.getValue().doubleValue()-handlingFee.doubleValue(),8);

        // 去掉手续费
        BigDecimal handlingFee = BigDecimal.ZERO;
        BigDecimal facePoint = dto.getValue();
        BigDecimal faceAddBalance = MathUtils.setScale(facePoint.doubleValue() * config.getPointPrice().doubleValue());

        //积分兑换余额
        integralRecordService.outer(userId, dto.getValue(), IntegralConstant.OuterMode.POINT_TO_BALANCE,
                IntegralConstant.IntegralModelType.POINT_TO_BALANCE, userId, "积分兑换余额");


        addBalance(userId, faceAddBalance, "", BillConstant.InnerMode.POINT_TO_BALANCE);

        PointToBalanceRecordEntity pointToBalanceRecordEntity = new PointToBalanceRecordEntity();
        pointToBalanceRecordEntity.setUserId(userId);
        pointToBalanceRecordEntity.setRealName(optionUserVerifiedEntity.getRealName());
        pointToBalanceRecordEntity.setMobile(account.getMobile());
        pointToBalanceRecordEntity.setGivePoint(dto.getValue());
        pointToBalanceRecordEntity.setFacePoint(facePoint);
        pointToBalanceRecordEntity.setHandlingFee(handlingFee);
        pointToBalanceRecordEntity.setFaceAddBalance(faceAddBalance);
        pointToBalanceRecordService.create(pointToBalanceRecordEntity);

    }



    @Override
    public PointToBalanceComputerVO pointGiveAwayComputer(Long userId, PointToBalanceDTO dto) {
        AccountEntity account = accountService.getUserById(userId, true);
        UserVerifiedEntity optionUserVerifiedEntity = userVerifiedService.loadById(userId, false);
        if(ObjectUtil.isNull(optionUserVerifiedEntity))
        {
            throw new RRException("您还没有实名认证不能转赠");
        }

        UserIdentityAssetEntity optionUserAssetEntity = userIdentityAssetService.loadByIdForLock(userId, true);
        if(optionUserAssetEntity.getIntegralAble().compareTo(dto.getValue())<0)
        {
            throw new RRException("您的可用积分不足");
        }

        PointConfig config = pointConfigService.loadConfig(true);

//        BigDecimal giveAwayHandlingFeeRatio = config.getGiveAwayHandlingFeeRatio();
//        BigDecimal handlingFee = MathUtils.setScaleDown(dto.getValue().doubleValue() * giveAwayHandlingFeeRatio.doubleValue() / 100, 8);
//        BigDecimal facePoint = MathUtils.setScaleDown(dto.getValue().doubleValue()-handlingFee.doubleValue(),8);

        // 去掉手续费
        BigDecimal handlingFee = BigDecimal.ZERO;
        BigDecimal facePoint = dto.getValue();

        BigDecimal faceAddBalance = MathUtils.setScale(facePoint.doubleValue() * config.getPointPrice().doubleValue());

        return PointToBalanceComputerVO.builder().facePoint(facePoint).handlingFee(handlingFee).faceAddBalance(faceAddBalance).build();
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void balanceGiveAway(Long userId, BalanceGiveAwayDTO dto) {
        if(userId.equals(dto.getUserObjId()))
        {
            throw new RRException("不能转赠给自己");
        }

        AccountEntity account = accountService.getUserById(userId, true);
        AccountEntity accounted = accountService.getUserById(dto.getUserObjId(), true);


        UserVerifiedEntity  optionUserVerifiedEntity = userVerifiedService.loadById(userId, false);
        if(ObjectUtil.isNull(optionUserVerifiedEntity))
        {
            throw new RRException("您还没有实名认证不能转赠");
        }
        UserVerifiedEntity userVerifiedEntity = userVerifiedService.loadById(dto.getUserObjId(), false);
        if(ObjectUtil.isNull(userVerifiedEntity))
        {
            throw new RRException("被转赠的用户没有实名认证");
        }

        UserIdentityAssetEntity optionUserAssetEntity = userIdentityAssetService.loadByIdForLock(userId, true);
        String pass = new Sha256Hash(dto.getPayPassword(), UserIdentityAssetServiceImpl.PASS_SALT).toHex();

        if(ObjectUtil.isEmpty(optionUserAssetEntity.getPayPass()))
        {
            throw new RRException("支付密码没设置",99999);
        }

        if(!optionUserAssetEntity.getPayPass().equals(pass))
        {
            throw new RRException("支付密码错误");
        }

        if(optionUserAssetEntity.getBalance().compareTo(dto.getValue())<0)
        {
            throw new RRException("您的余额不足");
        }

        addBalance(dto.getUserObjId(), dto.getValue(), "", BillConstant.InnerMode.BALANCE_GIVE_AWAY,
                String.format("用户%s(%s)转账",optionUserVerifiedEntity.getRealName(), PatternUtils.insensitiveOfPhone(account.getMobile())));

        subBalance(userId,dto.getValue(),"",BillConstant.OuterMode.BALANCE_GIVE_AWAY,
                String.format("余额转账给用户%s(%s)",userVerifiedEntity.getRealName(), PatternUtils.insensitiveOfPhone(accounted.getMobile())));


        BalanceGiveAwayEntity balanceGiveAwayEntity = new BalanceGiveAwayEntity();
        balanceGiveAwayEntity.setGiveUserId(userId);
        balanceGiveAwayEntity.setGiveRealName(optionUserVerifiedEntity.getRealName());
        balanceGiveAwayEntity.setGiveMobile(account.getMobile());


        balanceGiveAwayEntity.setAcceptUserId(dto.getUserObjId());
        balanceGiveAwayEntity.setAcceptRealName(userVerifiedEntity.getRealName());
        balanceGiveAwayEntity.setAcceptMobile(accounted.getMobile());
        balanceGiveAwayEntity.setGiveBalance(dto.getValue());
        balanceGiveAwayService.create(balanceGiveAwayEntity);

    }

    @Override
    public void adjustBalance(GiveBalanceDTO dto) {
        AccountEntity accounted = accountService.getUserById(dto.getUserObjId(), true);
        UserIdentityAssetEntity optionUserAssetEntity = userIdentityAssetService.loadByIdForLock(accounted.getId(), true);
        if(dto.getAdded())
        {
//            addBalance(dto.getUserObjId(), dto.getValue(), "", BillConstant.InnerMode.PLATFORM_ADJUST,"平台转入");
            addBalance(dto.getUserObjId(), dto.getValue(), "", BillConstant.InnerMode.PLATFORM_ADJUST,"转入");
        }
        else
        {
            if(optionUserAssetEntity.getBalance().compareTo(dto.getValue())<0)
            {
                throw new RRException("会员的余额不足");
            }

            subBalance(accounted.getId(),dto.getValue(),"",BillConstant.OuterMode.PLATFORM_ADJUST,"平台调整");
        }

    }

    @Transactional
    @Override
    public void balanceToPoint(Long userId, BalanceToPointDTO dto) {
        AccountEntity account = accountService.getUserById(userId, true);
        UserVerifiedEntity optionUserVerifiedEntity = userVerifiedService.loadById(userId, false);
        if(ObjectUtil.isNull(optionUserVerifiedEntity))
        {
            throw new RRException("您还没有实名认证不能兑换");
        }

        UserIdentityAssetEntity optionUserAssetEntity = userIdentityAssetService.loadByIdForLock(userId, true);
        String pass = new Sha256Hash(dto.getPayPassword(), UserIdentityAssetServiceImpl.PASS_SALT).toHex();
        if(ObjectUtil.isEmpty(optionUserAssetEntity.getPayPass()))
        {
            throw new RRException("支付密码没设置",99999);
        }

        if(!optionUserAssetEntity.getPayPass().equals(pass))
        {
            throw new RRException("支付密码错误");
        }

        if(optionUserAssetEntity.getBalance().compareTo(dto.getValue())<0)
        {
            throw new RRException("您的余额不足");
        }



        PointConfig config = pointConfigService.loadConfig(true);
        BigDecimal pointPrice;
        if(chainProperties.getDynamicPointPrice()){
            pointPrice = chainService.pointPrice();
        } else {
            pointPrice = config.getPointPrice();
        }

        BigDecimal balanceToPointHandlingFeeRatio = config.getBalanceToPointHandlingFeeRatio();
        BigDecimal handlingFee = MathUtils.setScaleDown(dto.getValue().doubleValue() * balanceToPointHandlingFeeRatio.doubleValue() / 100, 2);
        BigDecimal faceBalance = MathUtils.setScaleDown(dto.getValue().doubleValue() - handlingFee.doubleValue(),2);

        BigDecimal faceAddPoint = MathUtils.setScale(faceBalance.doubleValue() / pointPrice.doubleValue(), 8);

        // 保存记录
        BalanceToPointRecordEntity balanceToPointRecordEntity = new BalanceToPointRecordEntity();
        balanceToPointRecordEntity.setUserId(userId);
        balanceToPointRecordEntity.setRealName(optionUserVerifiedEntity.getRealName());
        balanceToPointRecordEntity.setMobile(account.getMobile());
        balanceToPointRecordEntity.setGiveBalance(dto.getValue());
        balanceToPointRecordEntity.setFaceBalance(faceBalance);
        balanceToPointRecordEntity.setHandlingFee(handlingFee);
        balanceToPointRecordEntity.setFaceAddPoint(faceAddPoint);
        balanceToPointRecordEntity.setPointPrice(pointPrice);
        balanceToPointRecordService.create(balanceToPointRecordEntity);

        // 减余额、生成账单
        subBalance(userId, dto.getValue(), String.valueOf(balanceToPointRecordEntity.getId()), BillConstant.OuterMode.BALANCE_TO_POINT, "余额转积分");

        // 余额转积分
        IntegralRecord integralRecord = new IntegralRecord();
        integralRecord.setUserId(userId);
        integralRecord.setValue(faceAddPoint);
        integralRecord.setBillType(BillConstant.BillMode.INCOME);
        integralRecord.setOuterMode(IntegralConstant.OuterMode.EMPTY);
        integralRecord.setInnerMode(IntegralConstant.InnerMode.BALANCE_TO_POINT);
        integralRecord.setModelType(IntegralConstant.IntegralModelType.BALANCE_TO_POINT);
        integralRecord.setModelId(balanceToPointRecordEntity.getId());
        integralRecord.setRemark("余额转积分");
        integralRecordService.inner(integralRecord);
    }

    @Override
    public BalanceToPointComputerVO balanceToPointComputer(Long userId, BalanceToPointDTO dto) {
        UserVerifiedEntity optionUserVerifiedEntity = userVerifiedService.loadById(userId, false);
        if(ObjectUtil.isNull(optionUserVerifiedEntity))
        {
            throw new RRException("您还没有实名认证不能转赠");
        }

        UserIdentityAssetEntity optionUserAssetEntity = userIdentityAssetService.loadByIdForLock(userId, true);
        if(optionUserAssetEntity.getBalance().compareTo(dto.getValue())<0)
        {
            throw new RRException("您的可用积分不足");
        }

        if (BigDecimal.ZERO.compareTo(dto.getValue()) == 0) {
            BalanceToPointComputerVO.builder().faceBalance(BigDecimal.ZERO).handlingFee(BigDecimal.ZERO).faceAddPoint(BigDecimal.ZERO).build();
        }


        PointConfig config = pointConfigService.loadConfig(true);

        BigDecimal pointPrice;
        if (chainProperties.getDynamicPointPrice()) {
            pointPrice = chainService.pointPrice();
        } else {
            pointPrice = config.getPointPrice();
        }

        BigDecimal balanceToPointHandlingFeeRatio = config.getBalanceToPointHandlingFeeRatio();
        BigDecimal handlingFee = MathUtils.setScaleDown(dto.getValue().doubleValue() * balanceToPointHandlingFeeRatio.doubleValue() / 100, 2);
        BigDecimal faceBalance = MathUtils.setScaleDown(dto.getValue().doubleValue() - handlingFee.doubleValue(),2);

        BigDecimal faceAddPoint = MathUtils.setScale(faceBalance.doubleValue() / pointPrice.doubleValue(), 8);

        return BalanceToPointComputerVO.builder().faceBalance(faceBalance).handlingFee(handlingFee).faceAddPoint(faceAddPoint).build();
    }

    @Override
    public void adjustIntegral(GiveBalanceDTO dto) {
        AccountEntity accounted = accountService.getUserById(dto.getUserObjId(), true);
        UserIdentityAssetEntity optionUserAssetEntity = userIdentityAssetService.loadByIdForLock(accounted.getId(), true);
        if (dto.getAdded()) {
            // 平台增加积分余额
            IntegralRecord integralRecord = new IntegralRecord();
            integralRecord.setUserId(dto.getUserObjId());
            integralRecord.setValue(dto.getValue());
            integralRecord.setBillType(BillConstant.BillMode.INCOME);
            integralRecord.setOuterMode(IntegralConstant.OuterMode.EMPTY);
            integralRecord.setInnerMode(IntegralConstant.InnerMode.PLATFORM_ADJUST);
            integralRecord.setModelType(IntegralConstant.IntegralModelType.PLATFORM_ADJUST);
            integralRecord.setRemark("平台调整");
            integralRecordService.inner(integralRecord);
        } else {
            if (optionUserAssetEntity.getIntegralAble().compareTo(dto.getValue()) < 0) {
                throw new RRException("会员的积分不足");
            }
            // 平台减少积分余额
            integralRecordService.outer(dto.getUserObjId(), dto.getValue(), IntegralConstant.OuterMode.PLATFORM_ADJUST,
                    IntegralConstant.IntegralModelType.PLATFORM_ADJUST, dto.getUserObjId(), "平台调整");
        }
    }

    @Override
    public void subVoucher(Long userId, BigDecimal subMoney, String outTradeNo, BillConstant.OuterMode outerModel) {
        //资产
//        UserIdentityAssetEntity userIdentity = userIdentityAssetService.updateBalance(userId, subMoney, false);

        UserIdentityAssetEntity userIdentity = userIdentityAssetService.updateVoucher(userId, subMoney, false);

        //生成充值订单账单明细，保存支出账单
        this.saveExpenditureVoucherBill(userIdentity, subMoney, outTradeNo, outerModel);
    }
}
